package fileIO;

/*
 * 加密算法，密钥文件，加密文件
 得到密钥的md5值，将md5值的ASCII码相加得到一个行数，
 产生二维BYTE数组，row等于行数，列数＝加密文件字节数／（行数－1），
 最后一行的列数为加密文件字节数％（行数－1），将字节依次一行一行放入数组，
 除最后一行外，对其余行数组转置
 此加密算法有严重的问题，加密多大的文件占用多大的内存空间
 加密太慢了：45.5M的文件用时4分钟，同一文件只作读入后写出操作用时9秒
 修改后用时160秒
 使用多线程
 */
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import mytool.Time;

public class MyEncript {
	private static RandomAccessFile raf;

	private static RandomAccessFile out;

	public static void main(String[] args) throws Exception {
		// File f = new File("/home/tarena/Desktop/2.txt");
		// File f1 = new File("/home/tarena/Desktop/3.txt");
		File f = new File("/home/tarena/Desktop/mysql_linux.zip");
		File f1 = new File("/home/tarena/Desktop/mysql_linux-encripted.zip");
		Time.start();
//		 decript(f, f1);
		encript(f, f);
		Time.end();

	}

	private static void encript(File keyFile, File tobeEncripted)
			throws IOException, NoSuchAlgorithmException {

		FileInputStream in = new FileInputStream(keyFile);
		byte[] buf = new byte[1024];
		MessageDigest md5 = MessageDigest.getInstance("md5");
		int numRead;
		while ((numRead = in.read(buf)) != -1) {
			md5.update(buf, 0, numRead);
		}
		in.close();
		byte[] bs = md5.digest();
		int sum = 0;
		for (byte b : bs) {
			sum += b & 0xff;
		}
		String absolutePath = keyFile.getAbsolutePath();
		String s = absolutePath.substring(0, absolutePath.length() - 4)
				+ "-encripted"
				+ absolutePath.substring(absolutePath.length() - 4);
		File encripted = new File(s);
		raf = new RandomAccessFile(tobeEncripted, "rw");
		out = new RandomAccessFile(encripted, "rw");
		int col = sum;
		long row = tobeEncripted.length() / col;
		int threadnum = 5;
		int range = (int) (row / threadnum);
//		int range = 1;
		byte[] by = new byte[col];

		RW rw1 = new RW(0, range, raf, out, by, col);
		rw1.start();
		RW rw2 = new RW(range, 2 * range, raf, out, by, col);
		rw2.start();
		RW rw3 = new RW(2 * range, 3 * range, raf, out, by, col);
		rw3.start();
		RW rw4 = new RW(3 * range, 4 * range, raf, out, by, col);
		rw4.start();
		RW rw5 = new RW(4 * range, 5 * range, raf, out, by, col);
		rw5.start();
		raf.seek(col * row);
		out.seek(col * row);

		// for (int j = 1; j <= row; j++) {
		// raf.read(by);
		// for (int x = col - 1; x >= 0; x--) {
		// out.write(by[x]);
		// }
		// }
		if (tobeEncripted.length() % col != 0) {
			by = new byte[(int) (tobeEncripted.length() % col)];
			raf.read(by);
			out.write(by);
		}
//		raf.close();
//		out.close();

	}

	private static void decript(File keyFile, File tobeDecripted)
			throws Exception {
		FileInputStream in = new FileInputStream(keyFile);
		byte[] buf = new byte[1024];
		MessageDigest md5 = MessageDigest.getInstance("md5");
		int numRead;
		while ((numRead = in.read(buf)) != -1) {
			md5.update(buf, 0, numRead);
		}
		in.close();
		byte[] bs = md5.digest();
		int sum = 0;
		for (byte b : bs) {
			sum += b & 0xff;
		}
		String absolutePath = keyFile.getAbsolutePath();
		String s = absolutePath.substring(0, absolutePath.length() - 4)
				+ "-decripted"
				+ absolutePath.substring(absolutePath.length() - 4);
		File decripted = new File(s);
		raf = new RandomAccessFile(tobeDecripted, "rw");
		out = new RandomAccessFile(decripted, "rw");
		int col = sum;
		long row = tobeDecripted.length() / col;
		int threadnum = 5;
		int range = (int) (row / threadnum);
		byte[] by = new byte[col];

		RW rw1 = new RW(0, range, raf, out, by, col);
		rw1.start();
		RW rw2 = new RW(range, 2 * range, raf, out, by, col);
		rw2.start();
		RW rw3 = new RW(2 * range, 3 * range, raf, out, by, col);
		rw3.start();
		RW rw4 = new RW(3 * range, 4 * range, raf, out, by, col);
		rw4.start();
		RW rw5 = new RW(4 * range, 5 * range, raf, out, by, col);
		rw5.start();
		raf.seek(col * row);
		out.seek(col * row);

//		for (int j = 1; j <= row; j++) {
//			raf.read(by);
//			for (int x = col - 1; x >= 0; x--) {
//				out.write(by[x]);
//			}
//		}

		if (tobeDecripted.length() % col != 0) {
			by = new byte[(int) (tobeDecripted.length() % col)];
			raf.read(by);
			out.write(by);
		}
//		raf.close();
//		out.close();
	}

}

class RW extends Thread {
	int start;

	int end;

	RandomAccessFile raf;

	RandomAccessFile out;

	byte[] by;

	int col;

	public RW(int start, int end, RandomAccessFile raf, RandomAccessFile out,
			byte[] by, int col) {
		this.start = start;
		this.end = end;
		this.raf = raf;
		this.out = out;
		this.by = by;
		this.col = col;
	}

	@Override
	public void run() {
		try {
			System.out.println(col*start);
			raf.seek(col * start);
			out.seek(col * start);
			for (int i = start; i < end; i++) {
				raf.read(by);
				for (int x = col - 1; x >= 0; x--) {
					out.write(by[x]);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

	}
}
